package com.spvs.system.section;

import com.spvs.common.core.domain.R;
import com.spvs.common.core.web.domain.AjaxResult;
import com.spvs.system.domain.FileChunks;
import com.spvs.system.service.IFileChunksService;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.Timestamp;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;

import static com.spvs.common.core.web.domain.AjaxResult.error;
import static com.spvs.common.core.web.domain.AjaxResult.success;

@RestController
@RequestMapping("/fileChunk")
public class FileChunkUploadController {


    private static final String UPLOAD_DIR = "E:/documents/";

    @Autowired
    private IFileChunksService fileChunkRepository;

    @Autowired
    private ISysFileService iSysFileService;

    @PostMapping("/uploadChunk")
    public AjaxResult uploadChunk(@RequestParam("file") MultipartFile file,
                                  @RequestParam("md5") String md5,
                                  @RequestParam("chunkNumber") int chunkNumber,
                                  @RequestParam("totalChunks") int totalChunks,
                                  @RequestParam("name") String name) {
        try {

//                // 查询切片元数据
//                FileChunks fileChunks = new FileChunks();
//                fileChunks.setFileMd5(md5);
//                List<FileChunks> chunks = fileChunkRepository.selectFileChunksList(fileChunks);
//                if(chunks.size()>0) {
//                    fileChunks.setChunkNumber(chunks.get(0).getInfoExtend1());
//                    List<FileChunks> chunks1 = fileChunkRepository.selectFileChunksList(fileChunks);
//                    if (chunks1.size() > 0) {
//                        return success(chunks1.get(0).getInfoExtend2());
//                    }
//                }
            // 创建上传目录（如果不存在）

            File uploadDir = new File(UPLOAD_DIR + md5);
            if (!uploadDir.exists()) {
                uploadDir.mkdirs();
            }

            // 保存切片到服务器
            String chunkFileName = md5 + ".part" + chunkNumber;
            Path path = Paths.get(UPLOAD_DIR + md5 + "/" + chunkFileName);
            Files.write(path, file.getBytes());

            // 记录切片元数据到数据库

            FileChunks fileChunk = new FileChunks();
            fileChunk.setFileMd5(md5);
            fileChunk.setChunkNumber(chunkNumber);
            fileChunk.setChunkSize(file.getSize());
            fileChunk.setUploadTime(new Timestamp(new Date().getTime()));
            fileChunk.setFilePath(path.toString());
            fileChunk.setInfoExtend1(totalChunks);
            fileChunkRepository.insertFileChunks(fileChunk);

            if(totalChunks == chunkNumber){
                 mergeChunks(md5,name);
                String filePath = UPLOAD_DIR + sanitizeFileName(name);
                MultipartFile multipartFile = getMultipartFileFromPath(filePath);

                String url = iSysFileService.uploadFile(multipartFile);
                fileChunk.setInfoExtend2(url);
                fileChunkRepository.updateFileChunks(fileChunk);

                return  success(iSysFileService.uploadFile(multipartFile));
            }


            return success("切片上传成功第: " + chunkNumber+"片");

        } catch (IOException e) {
            e.printStackTrace();
            return error("切片上传失败: " + e.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return success();
    }

    @PostMapping("/selectChunkNumberByMd5")
    public AjaxResult selectChunkNumberByMd5(@RequestBody Map<String, String> requestBody) {
        // 查询切片元数据
        FileChunks fileChunks = new FileChunks();
        if(null!=requestBody){
            fileChunks.setFileMd5(requestBody.get("md5"));
            List<FileChunks> chunks = fileChunkRepository.selectFileChunksList(fileChunks);
            if(chunks.size()>0) {
                fileChunks.setChunkNumber(chunks.get(0).getInfoExtend1());
                List<FileChunks> chunks1 = fileChunkRepository.selectFileChunksList(fileChunks);
                if (chunks1.size() > 0) {
                    return success(chunks1.get(0).getInfoExtend2());
                }
            }
            return success(chunks.size());
        }
        return success("md5值为空");
    }
    @PostMapping("/mergeChunks")
    public AjaxResult mergeChunks(String md5,String name) {
        try {
            // 查询切片元数据
            FileChunks fileChunks = new FileChunks();
            fileChunks.setFileMd5(md5);
            List<FileChunks> chunks = fileChunkRepository.selectFileChunksList(fileChunks);

            // 检查切片是否为空
            if (chunks == null || chunks.isEmpty()) {
                return error("未找到与 MD5 值 " + md5 + " 相关的切片");
            }

            // 确保切片按顺序合并
            chunks.sort(Comparator.comparingInt(FileChunks::getChunkNumber));

            // 创建目标文件路径
            Path targetPath = Paths.get(UPLOAD_DIR + name);

            // 检查并创建目标文件的父目录
            if (!Files.exists(targetPath.getParent())) {
                Files.createDirectories(targetPath.getParent());
            }

            // 检查目标文件是否已存在
            if (!Files.exists(targetPath)) {
                // 创建目标文件
                Files.createFile(targetPath);
            }



            // 合并切片
            try (FileOutputStream fos = new FileOutputStream(targetPath.toFile(), true)) {
                for (FileChunks chunk : chunks) {
                    Path chunkPath = Paths.get(chunk.getFilePath());

                    // 检查切片路径是否为文件
                    if (!Files.isRegularFile(chunkPath)) {
                        return error("切片路径 " + chunk.getFilePath() + " 不是一个有效的文件");
                    }

                    // 检查切片是否存在
                    if (!Files.exists(chunkPath)) {
                        return error("切片 " + chunk.getFilePath() + " 不存在");
                    }

                    // 检查切片是否可读
                    if (!Files.isReadable(chunkPath)) {
                        return error("切片 " + chunk.getFilePath() + " 无法读取，请检查文件权限");
                    }

                    try (FileInputStream fis = new FileInputStream(chunkPath.toFile())) {
                        byte[] buffer = new byte[4096];
                        int bytesRead;
                        while ((bytesRead = fis.read(buffer)) != -1) {
                            fos.write(buffer, 0, bytesRead);
                        }
                    }

                    // 删除已合并的切片
                    try {
                        Files.delete(chunkPath);
                    } catch (IOException e) {
                        e.printStackTrace();
                        // 记录日志，但不影响合并逻辑
                    }
                }
            }

            return success(targetPath.toString());
        } catch (Exception e) {
            e.printStackTrace();
            return error("文件合并失败: " + e.getMessage());
        }
    }

    public static MultipartFile getMultipartFileFromPath(String filePath) throws IOException {
        // 根据文件路径创建File对象
        File file = new File(filePath);

        // 使用FileInputStream读取文件内容
        try (FileInputStream inputStream = new FileInputStream(file)) {
            // 创建MockMultipartFile对象
            return new MockMultipartFile(
                    file.getName(),  // 文件名
                    file.getName(),  // 原始文件名
                    "application/octet-stream",  // 文件类型
                    inputStream  // 文件内容
            );
        }
    }
    private String sanitizeFileName(String fileName) {
        // 移除非法字符
        return fileName.replaceAll("[^a-zA-Z0-9._-]", "");
    }
}
